/*    Copyright 2010 Tobias Marschall
 *
 *    This file is part of MoSDi.
 *
 *    MoSDi is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    MoSDi is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with MoSDi.  If not, see <http://www.gnu.org/licenses/>.
 */

package mosdi.subcommands;

import mosdi.util.Alphabet;
import mosdi.util.Combinatorics;
import mosdi.util.Log;
import mosdi.util.iterators.IupacAbelianPatternGenerator;

public class IupacAbelianGenSubcommand extends Subcommand {
	
	@Override
	public String usage() {
		return
		super.usage()+" [options] <length>\n" +
		"\n" +
		"Options:\n" +
		"  -m minimum number of 1-/2-/3-/4-valued letters, default: \"0,0,0,0\"\n" +
		"  -M maximum number of 1-/2-/3-/4-valued letters, default: \"<length>,0,0,0\"\n" +
		"  -P <max-prob> generate only those strings such that the probability that a\n" +
		"     random string (of length <length> with independent uniformly distributed characters)\n" +
		"     matches each generated string is below <max-prob>. (default: 1.0)\n" +
		"  -n for each pattern, print number of strings which match that pattern";
	}
	
	@Override
	public String description() {
		return "Enumerates abelian patterns of IUPAC characters.";
	}

	@Override
	public String name() {
		return "iupac-abelian-gen";
	}

	@Override
	public int run(String[] args) {
		parseOptions(args, 1, "m:M:P:n");

		// Option dependencies
		// -- none --

		// Mandatory arguments
		int length = getIntArgument(0);

		// Options
		int[] minFrequencies = {0,0,0,0};
		minFrequencies = getRangedIntTupleOption("m", 4, 0, length, minFrequencies);
		int[] maxFrequencies = {length,0,0,0};
		maxFrequencies = getRangedIntTupleOption("M", 4, 0, length, maxFrequencies);
		double maxProb = getRangedDoubleOption("P", 0.0, 1.0, 1.0);
		boolean printMultiplicity = getBooleanOption("n", false); 

		IupacAbelianPatternGenerator apg = new IupacAbelianPatternGenerator(length, minFrequencies, maxFrequencies, maxProb);
		Alphabet iupacAlphabet = apg.getAlphabet();
		for (int[] abelianPattern : apg) {
			StringBuilder sb = new StringBuilder();
			for (int i=0; i<abelianPattern.length; ++i) {
				if (abelianPattern[i]>0) {
					sb.append(iupacAlphabet.get(i));				
					sb.append(Integer.toString(abelianPattern[i]));
				}
			}
			if (printMultiplicity) {
				// calculate number of string in expanded abelian pattern
				double logNumber = Combinatorics.logMultinomial(length, abelianPattern);
				sb.append(String.format(" %d", (long)Math.round(Math.exp(logNumber))));
			}
			Log.println(Log.Level.STANDARD, sb.toString());
		}
		return 0;
	}
}
